package org.streets.context.internal;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;

import org.apache.tapestry5.ioc.annotations.SubModule;
import org.apache.tapestry5.ioc.def.ModuleDef;
import org.apache.tapestry5.ioc.def.ServiceDef;
import org.streets.commons.util.ClassUtils;
import org.streets.commons.util.ReflectionUtils;
import org.streets.commons.util.StringUtils;
import org.streets.commons.util.ReflectionUtils.MethodCallback;
import org.streets.commons.util.ReflectionUtils.MethodFilter;
import org.streets.annotations.Detail;
import org.streets.annotations.Portal;
import org.streets.context.definition.FunctionDefinition;
import org.streets.context.definition.ModuleDefinition;

/**
 * Main module information . It's generated by logix.
 * 
 * And use this class instance for build hivemind registry.
 * 
 * @author dzb
 */
public class ModuleDefinitionImpl implements ModuleDefinition {
	// module id
	protected String id;
	// module name
	protected String name;
	// 
	protected String hint;
	//
	protected String memo; 
	//
	private Class<?> builder;
	//
	private String portal = "";
	
	private String icon;

	private ModuleDefinition parent;
	
	private final List<ModuleDefinition> sub_modules = new ArrayList<ModuleDefinition>();
	private final List<FunctionDefinition> functions = new ArrayList<FunctionDefinition>();

	// 如果为1 就表示被HiveModule标注过了 可以对外显示
	private int type = 0;
	
	private int index = -1;

	//
	private boolean inited = false;

	public ModuleDefinitionImpl(Class<?> moduleClass) {
		this.builder = moduleClass;
		this.id = resolveId(moduleClass);
	}
	
	// 缺省id使用module前的字母
	ModuleDefinitionImpl(final Collection allDefs, ModuleDef def,ModuleDefinition parent) {
		this(def.getBuilderClass());
		this.parent = parent;
		init(allDefs, def);
	}
	
	public boolean isInited() {
		return inited;
	}
	
	private void init(final Collection<ModuleDef> allDefs, ModuleDef def) {
		
		Detail hm = builder.getAnnotation(Detail.class);
		if (hm != null) {
			this.id = hm.id();
			this.name = hm.name();
			this.hint = hm.hint();			
			this.type = 1;
			this.index = hm.index();
			this.icon = hm.icon();
		} 
		
		Portal pt = builder.getAnnotation(Portal.class);
		if (pt != null) {
			this.portal = pt.value();
		}
		
		if (StringUtils.isEmpty(this.id)) {
			this.id = resolveId(def.getBuilderClass());
		}
		// extract all service-points
		Set<String> ids = def.getServiceIds();
		for (String s_id : ids) {
			ServiceDef service_def = def.getServiceDef(s_id);
			Class<?> service_clz = service_def.getServiceInterface();
			ReflectionUtils.doWithMethods(service_clz, 
				new MethodCallback() {
					public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {						
						functions.add(new FunctionDefinitionImpl(ModuleDefinitionImpl.this, method));					
					}				
				}, 				
				new MethodFilter() {
					public boolean matches(Method method) {
						return method.getAnnotation(Detail.class) != null;
					}					
				});
		}
		
		//排序
		Collections.sort(functions, new Comparator<FunctionDefinition>(){
			public int compare(FunctionDefinition o1, FunctionDefinition o2) {
				return o1.getIndex() - o2.getIndex();
			}			
		});

		// init sub modules
		SubModule sm = (SubModule) def.getBuilderClass().getAnnotation(SubModule.class);		
		if (sm != null) {
			for (Class<?> clzz : sm.value()) {
				for (ModuleDef md : allDefs) {
					if (clzz.equals(md.getBuilderClass())) {
						ModuleDefinition mdi = new ModuleDefinitionImpl(allDefs, md,this);
						sub_modules.add(mdi);
					}
				}	
			}			
		}
		//排序
		Collections.sort(sub_modules, new Comparator<ModuleDefinition>(){
			public int compare(ModuleDefinition o1, ModuleDefinition o2) {
				return o1.getIndex() - o2.getIndex();
			}
			
		});

		this.inited = true;
	}
	
	private String resolveId(Class<?> moduleClass) {
		String builder_name = ClassUtils.getShortClassName(moduleClass).toLowerCase();
		int p = builder_name.indexOf("module");
		String result;
		if (p > 0) {
			result = builder_name.substring(0, p);
		} else {
			result = ClassUtils.getPackageName(moduleClass);
			result = result.substring(result.lastIndexOf(".")+1);
		}
		return result;
	}
	
	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public String getHint() {
		return hint;
	}
	
	public void setHint(String description) {
		this.hint = description;
	}
	
	public String getMemo() {
		return memo;
	}

	public void setMemo(String memo) {
		this.memo = memo;
	}

	public int getType() {
		return type;
	}

	public void setType(int type) {
		this.type = type;
	}
	
	public String getPortal() {
		return portal;
	}

	public void setPortal(String portal) {
		this.portal = portal;
	}

	public int getIndex() {
		return index;
	}

	public void setIndex(int index) {
		this.index = index;
	}

	public Class<?> getModuleClass() {
		return builder;
	}
	
	public List<ModuleDefinition> getSubModules() {
		return sub_modules;
	}
	
	public List<FunctionDefinition> getFunctions() {
		return functions;
	}
	
	public void clear() {
		functions.clear();
	}
	
	public ModuleDefinition getParent(){
		return parent;
	}
	
	public String getIcon(){
		return icon;
	}
}
